package com.stock.core.service.stock;

import com.stock.api.domain.stock.HistoryAnalysisBean;
import com.stock.api.domain.stock.StockHistoryBean;
import com.stock.api.service.stock.HistoryAnalysisService;
import com.stock.api.service.stock.StockHistoryService;
import com.stock.api.util.StockUtils;
import com.stock.comm.util.DateUtil;
import com.stock.comm.util.PropertyUtils;
import com.stock.core.persistence.reader.stock.StockCodeReaderMapper;
import com.stock.core.persistence.writer.stock.HistoryAnalysisWriterMapper;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * <p>类说明</p>
 *
 * @author 张峰 zfvip_it@163.com
 * @createTime: 2016/9/18 9:16
 */
@Service("historyAnalysisService")
public class HistoryAnalysisServiceImpl implements HistoryAnalysisService {

    private static final Logger LOGGER = LoggerFactory.getLogger(HistoryAnalysisServiceImpl.class);

    @Resource
    private HistoryAnalysisWriterMapper historyAnalysisWriterMapper;

    @Resource
    private StockHistoryService stockHistoryService;

    @Resource
    private StockCodeReaderMapper stockCodeReaderMapper;

    @Resource
    private RedisTemplate redisTemplate;

    /**
     * 创建线程池
     */
    ExecutorService pool = null;


    /**
     * 分析股票历史数据数据
     *
     * @param stockCode
     * @param startDate
     * @throws Exception
     */
    public void analysisStockHistoryData(final String stockCode, String startDate) throws Exception {
        //1、默认买入给定日期的股票
        purchaseStockHistoryDate(stockCode, startDate);
        boolean flag = true;
        Date date = DateUtil.string2Date(startDate, DateUtil.DATESHORTFORMAT);
        //当前日期
        String currentDate = DateUtil.formatCurrentDate();
        while (flag) {
            //日期加1
            date = DateUtil.addDate(date, 1);
            //星期数
            String week = DateUtil.getDayOfWeek(date, 0);
            //自动跳过星期六和星期天
            if (!StringUtils.equals("6", week) && !StringUtils.equals("7", week)) {
                String stockDate = DateUtil.date2String(date, DateUtil.DATESHORTFORMAT);
                LOGGER.info("股票代码【" + stockCode + "】,日期【" + stockDate + "】");
                //读取历史收盘数据
                StockHistoryBean stockHistoryBean = stockHistoryService.getStockHistoryData(stockDate, stockCode);
                if (stockHistoryBean != null) {
                    //更新股票的当前价格
                    StockUtils.getStockPriceMap().put(stockCode, stockHistoryBean.getClosePrice());
                    //分析数据
                    analysiBusinessHistory(stockHistoryBean);
                }
            }
            LOGGER.info("日期比较：【" + currentDate.replaceAll("-", "") + "】,【" + DateUtil.date2String(date, DateUtil.DATESHORTFORMAT) + "】");
            //当前日期停止
            if (currentDate.replaceAll("-", "").equals(DateUtil.date2String(date, DateUtil.DATESHORTFORMAT)))
                flag = false;
        }
    }

    /**
     * 分析股票数据
     *
     * @param stockHistoryBean
     */
    public void analysiBusinessHistory(StockHistoryBean stockHistoryBean) throws Exception {
        //获取未买入或者未卖出的股票业务数据
        List<HistoryAnalysisBean> businessHistoryBeanList = historyAnalysisWriterMapper.selectHistoryAnalysis(stockHistoryBean);

        if (businessHistoryBeanList != null && !businessHistoryBeanList.isEmpty()) {
            //计算是否买入和卖出
            calcBusinessHistory(stockHistoryBean, businessHistoryBeanList);
        }
    }

    /**
     * 计算是否买入和卖出
     *
     * @param stockHistoryBean
     * @param historyAnalysisBeanList
     */
    private void calcBusinessHistory(final StockHistoryBean stockHistoryBean, final List<HistoryAnalysisBean> historyAnalysisBeanList) throws Exception {
        if (historyAnalysisBeanList != null) {
            int size = historyAnalysisBeanList.size();
            pool = Executors.newFixedThreadPool(size > 10 ? 10 : size);
            List<Future> rowResult = new CopyOnWriteArrayList<>();
            for (int i = 0; i < size; i++) {

                final int finalI = i;
                rowResult.add(pool.submit(new Runnable() {
                    @Override
                    public void run() {
                        HistoryAnalysisBean historyBean = historyAnalysisBeanList.get(finalI);
                        //1、计算涨跌幅 当前价-（买入或者卖出价格）/ （买入或者卖出价格）
                        BigDecimal changeRate = stockHistoryBean.getClosePrice().subtract(historyBean.getBusinessPrice()).divide(historyBean.getBusinessPrice(), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
                        //更新我的股票涨跌幅
                        StockUtils.getChangeRateMap().put(historyBean.getStockCode(), changeRate);
                        //成交方向  01:买入  02:卖出
                        if ((StringUtils.equals(historyBean.getBusinessDirection(), "02") && changeRate.doubleValue() <= PropertyUtils.getIntValue("historical.analysis.min", -2))
                                || StringUtils.equals(historyBean.getBusinessDirection(), "01")) {
                            if (changeRate.doubleValue() >= PropertyUtils.getIntValue("historical.analysis.max", 2) || (changeRate.doubleValue() <= PropertyUtils.getIntValue("historical.analysis.min", -2) && StringUtils.isBlank(historyBean.getIsBuy()))) { //涨幅大于卖出 //涨幅小于买入 并且买入的未买入
                                LOGGER.debug("【" + stockHistoryBean.getStockCode() + " " + stockCodeReaderMapper.selectByStockCode(stockHistoryBean.getStockCode()).getStockName() + "】涨跌幅：（" + stockHistoryBean.getClosePrice() + "-" + historyBean.getBusinessPrice() + ")/" + historyBean.getBusinessPrice() + " = " + changeRate);
                                if (StringUtils.equals(historyBean.getBusinessDirection(), "01")) {
                                    //原买入处理
                                    sellIn(changeRate, historyBean, stockHistoryBean);
                                } else if (StringUtils.equals(historyBean.getBusinessDirection(), "02") && StringUtils.isBlank(historyBean.getIsBuy()) &&
                                        (changeRate.doubleValue() <= PropertyUtils.getIntValue("historical.analysis.min", -2))) {
                                    //原卖出处理
                                    sellOut(changeRate, historyBean, stockHistoryBean);
                                }
                            }
                        }
                    }
                }));
            }
            //等待处理结果
            for (Future f : rowResult) {
                f.get();
            }
            //启动一次顺序关闭，执行以前提交的任务，但不接受新任务。如果已经关闭，则调用没有其他作用
            pool.shutdown();
        }
    }

    /**
     * @param stockHistoryBean
     * @param historyBean
     * @return
     */
    private HistoryAnalysisBean getHistoryAnalysisBean(StockHistoryBean stockHistoryBean, HistoryAnalysisBean historyBean) {
        HistoryAnalysisBean historyAnalysisBean = new HistoryAnalysisBean();
        historyAnalysisBean.setBusinessDate(stockHistoryBean.getStockDate());//成交日期
        historyAnalysisBean.setBusinessTime(DateUtil.formatCurrentDatetime());//成交时间
        historyAnalysisBean.setStockCode(stockHistoryBean.getStockCode());//股票代码
        historyAnalysisBean.setBusinessPrice(stockHistoryBean.getClosePrice());//成交价格
        historyAnalysisBean.setPreSalePrice(stockHistoryBean.getClosePrice().multiply(new BigDecimal(PropertyUtils.getIntValue("historical.analysis.max", 2)).divide(new BigDecimal(100))).add(stockHistoryBean.getClosePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));//预卖价格
        //计算成交数量
        int businessNumber = new BigDecimal(PropertyUtils.getIntValue("historical.analysis.amount", 10000)).divide(stockHistoryBean.getClosePrice(), 2).intValue();
        businessNumber = businessNumber / 100;
        businessNumber = businessNumber * 100;
        historyAnalysisBean.setBusinessNumber(businessNumber);
        historyAnalysisBean.setBusinessNumber(businessNumber);//成交数量
        historyAnalysisBean.setBusinessAmount(stockHistoryBean.getClosePrice().multiply(new BigDecimal(businessNumber)));//成交金额
        //计算手续费 按照万三计算，最少5元
        BigDecimal sumFare = historyAnalysisBean.getBusinessAmount().multiply(new BigDecimal(0.0003)).setScale(4, BigDecimal.ROUND_HALF_UP);
        historyAnalysisBean.setSumFare(sumFare);
        if (sumFare.doubleValue() < 5)
            historyAnalysisBean.setSumFare(new BigDecimal(5));

        historyAnalysisBean.setRsourceId(historyBean.getId());//来源ID
        //创建人
        historyAnalysisBean.setCreateUser("0000");
        historyAnalysisBean.setCreateDate(DateUtil.formatCurrentDate());
        historyAnalysisBean.setCreateTime(new Date());
        return historyAnalysisBean;
    }

    /**
     * 原买入处理
     *
     * @param changeRate
     * @param historyAnalysisBeanOld
     * @param stockHistoryBean
     */
    private void sellIn(BigDecimal changeRate, HistoryAnalysisBean historyAnalysisBeanOld, StockHistoryBean stockHistoryBean) {
        HistoryAnalysisBean historyAnalysisBean = getHistoryAnalysisBean(stockHistoryBean, historyAnalysisBeanOld);
        if (historyAnalysisBean.getBusinessNumber() > 0) {
            //成交方向  01:买入  02:卖出
            if (changeRate.intValue() > 1) {
                historyAnalysisBean.setBusinessDirection("02");//卖出
                historyAnalysisBean.setBusinessNumber(historyAnalysisBeanOld.getBusinessNumber());//成交数量
                historyAnalysisBean.setBusinessAmount(stockHistoryBean.getClosePrice().multiply(new BigDecimal(historyAnalysisBeanOld.getBusinessNumber())));//成交金额
                historyAnalysisBean.setPreSalePrice(null);//预买价格
                //计算手续费 按照万三计算，最少5元
                BigDecimal sumFare = historyAnalysisBean.getBusinessAmount().multiply(new BigDecimal(0.0003)).setScale(4, BigDecimal.ROUND_HALF_UP);
                historyAnalysisBean.setSumFare(sumFare);
                if (sumFare.doubleValue() < 5)
                    historyAnalysisBean.setSumFare(new BigDecimal(5));
            } else {
                historyAnalysisBean.setBusinessDirection("01");//买入
            }

            if (StringUtils.equals(historyAnalysisBean.getBusinessDirection(), "01") && StringUtils.isBlank(historyAnalysisBeanOld.getIsBuy())) {
                //新增
                historyAnalysisWriterMapper.insert(historyAnalysisBean);
                //更新买入标志
                historyAnalysisWriterMapper.updateIsBuyById(historyAnalysisBeanOld.getId());
                LOGGER.debug("买入股票【" + stockHistoryBean.getStockCode() + "  " + stockCodeReaderMapper.selectByStockCode(stockHistoryBean.getStockCode()).getStockName() + "】数量：" + historyAnalysisBean.getBusinessNumber() + " 成交单价：" + historyAnalysisBean.getBusinessPrice() + " 成交金额：" + historyAnalysisBean.getBusinessAmount());
            } else if (StringUtils.equals(historyAnalysisBean.getBusinessDirection(), "02") && historyAnalysisBeanOld.getOutId() == null) {
                //新增
                historyAnalysisWriterMapper.insert(historyAnalysisBean);
                //盈亏
                BigDecimal profitLoss = historyAnalysisBean.getBusinessAmount().subtract(historyAnalysisBeanOld.getBusinessAmount()).subtract(historyAnalysisBean.getSumFare()).setScale(4, BigDecimal.ROUND_HALF_UP);
                //更新卖出ID 和盈亏
                historyAnalysisWriterMapper.updateOutIdById(historyAnalysisBeanOld.getId(), historyAnalysisBean.getId(), profitLoss);
                LOGGER.debug("卖出股票【" + stockHistoryBean.getStockCode() + "  " + stockCodeReaderMapper.selectByStockCode(stockHistoryBean.getStockCode()).getStockName() + "】数量：" + historyAnalysisBean.getBusinessNumber() + " 成交单价：" + historyAnalysisBean.getBusinessPrice() + " 成交金额：" + historyAnalysisBean.getBusinessAmount() + " 盈利：" + profitLoss +
                        "买入数量：" + historyAnalysisBeanOld.getBusinessNumber() + "买入价格：" + historyAnalysisBeanOld.getBusinessPrice() + " 买入金额：" + historyAnalysisBeanOld.getBusinessAmount());
            }
            //更新缓存
            updateRedis(historyAnalysisBean);
        }
    }

    /**
     * 原卖出处理
     */
    private void sellOut(BigDecimal changeRate, HistoryAnalysisBean historyAnalysisBeanOld, StockHistoryBean stockHistoryBean) {
        HistoryAnalysisBean historyAnalysisBean = getHistoryAnalysisBean(stockHistoryBean, historyAnalysisBeanOld);
        //成交方向  01:买入  02:卖出
        historyAnalysisBean.setBusinessDirection("01");//买入
        //新增
        historyAnalysisWriterMapper.insert(historyAnalysisBean);
        //更新买入标志
        historyAnalysisWriterMapper.updateIsBuyById(historyAnalysisBeanOld.getId());
        //更新业务数据
        historyAnalysisWriterMapper.updateOutIdById(historyAnalysisBeanOld.getId(), historyAnalysisBean.getId(), null);
//        if (changeRate.intValue() > 1) {
//
//        } else {
//        }
        LOGGER.debug("买入股票【" + stockHistoryBean.getStockCode() + "  " + stockCodeReaderMapper.selectByStockCode(stockHistoryBean.getStockCode()).getStockName() + "】数量：" + historyAnalysisBean.getBusinessNumber() + " 成交单价：" + historyAnalysisBean.getBusinessPrice() + " 成交金额：" + historyAnalysisBean.getBusinessAmount());
        //更新缓存
        updateRedis(historyAnalysisBean);
    }



    /**
     * @param startDate
     */
    private void purchaseStockHistoryDate(String stockCode, String startDate) throws Exception {
        //1、清空数据
        historyAnalysisWriterMapper.deleteByStockCode(stockCode);

        //读取历史收盘数据
        StockHistoryBean stockHistoryBean = stockHistoryService.getStockHistoryData(startDate, stockCode);
        if (stockHistoryBean != null) {
            //新增业务数据
            HistoryAnalysisBean historyAnalysisBean = new HistoryAnalysisBean();
            historyAnalysisBean.setBusinessDate(stockHistoryBean.getStockDate());//成交日期
            historyAnalysisBean.setBusinessTime(DateUtil.formatCurrentDatetime());//成交时间
            historyAnalysisBean.setStockCode(stockCode);//股票代码
            historyAnalysisBean.setBusinessPrice(stockHistoryBean.getClosePrice());//成交价格
            historyAnalysisBean.setPreSalePrice(stockHistoryBean.getClosePrice().multiply(new BigDecimal(0.05)).add(stockHistoryBean.getClosePrice()).setScale(4, BigDecimal.ROUND_HALF_UP));//预卖价格
            //计算成交数量
            int businessNumber = new BigDecimal(10000).divide(stockHistoryBean.getClosePrice(), 2).intValue();
            businessNumber = businessNumber / 100;
            businessNumber = businessNumber * 100;
            historyAnalysisBean.setBusinessNumber(businessNumber);//成交数量
            historyAnalysisBean.setBusinessAmount(stockHistoryBean.getClosePrice().multiply(new BigDecimal(businessNumber)));//成交金额
            //计算手续费 按照万三计算，最少5元
            BigDecimal sumFare = historyAnalysisBean.getBusinessAmount().multiply(new BigDecimal(0.0003)).setScale(4, BigDecimal.ROUND_HALF_UP);
            historyAnalysisBean.setSumFare(sumFare);
            //成交方向  01:买入  02:卖出
            historyAnalysisBean.setBusinessDirection("01");//买入
            //盈亏
            historyAnalysisBean.setProfitLoss(new BigDecimal(0));
            //创建人
            historyAnalysisBean.setCreateUser("0000");
            historyAnalysisBean.setCreateDate(DateUtil.formatCurrentDate());
            historyAnalysisBean.setCreateTime(new Date());
            //新增数据
            historyAnalysisWriterMapper.insert(historyAnalysisBean);
        }
    }

    /**
     * 更新缓存
     *
     * @param historyAnalysisBean
     */
    private void updateRedis(HistoryAnalysisBean historyAnalysisBean) {
        if (StringUtils.equals(historyAnalysisBean.getBusinessDirection(), "01")) {//买入
            //根据股票代码获取买入总金额
            BigDecimal totalMarketValue = historyAnalysisWriterMapper.getTotalMarketValue(historyAnalysisBean.getStockCode());
            //获取缓存总金额
            Object maxTatalAmount = redisTemplate.opsForValue().get(historyAnalysisBean.getStockCode() + "HistoryAnalysisMaxTotalAmount");
            if (maxTatalAmount == null)
                maxTatalAmount = "0";

//            BigDecimal totalMarketValue = StockUtils.getStockPrice(historyAnalysisBean.getStockCode()).multiply(new BigDecimal(totalNumber));
            if (totalMarketValue.subtract(new BigDecimal(maxTatalAmount + "")).doubleValue() > 0) {
                redisTemplate.opsForValue().set(historyAnalysisBean.getStockCode() + "HistoryAnalysisMaxTotalAmount", totalMarketValue);
            }
        }
    }

}
